//
// Created by 32827 on 2023/12/6.
//
#include "yzl_spi_sd.h"
//下面是MicroSD的初始化及读写函数
void SPI1_ReadWriteByteStart(){
    yzl_softport_spi_start(MicroSD_SPI);
}
char SPI1_ReadWriteByte(char data){
    return yzl_softport_spi_transmit_byte8(MicroSD_SPI,data);
}
void SPI1_ReadWriteByteEnd(){
    yzl_softport_spi_end(MicroSD_SPI);
}
char SentCommandToMicroSD(char cmd,int data,char crc)
{
    MicroSD_CS_SET;
    SPI1_ReadWriteByte(0xff);
    MicroSD_CS_RESET;

    char result=0,times=0;
    MicroSD_CS_SET;//禁止SD卡片选 同步时钟
    SPI1_ReadWriteByte(0xff);
    MicroSD_CS_RESET;//开始传输
    SPI1_ReadWriteByte(cmd);
    for(times=0;times<4;times++)
    {
        SPI1_ReadWriteByte((data>>24)&0xff);
        data<<=8;
    }
    SPI1_ReadWriteByte(crc);
    SPI1_ReadWriteByte(0xff); //八个时钟
    times=0;
    do{  //读取后8位
        result = SPI1_ReadWriteByte(0xFF);
        times++;
    }
    while((result==0xff)&&(times<50));
    return result;
}
///---------------- 回复类型处理 ----------------

uint8_t sd_result[32];
uint8_t *sd_response_0(char cmd){
    uint16_t times=0;
    do{  //读取后8位
        sd_result[0] = SPI1_ReadWriteByte(0xFF);
        times++;
    }
    while((sd_result[0]==0xff)&&(times<50));
    return sd_result;
}
uint8_t *sd_response_1(char cmd){
    uint16_t times=0;
    do{
        sd_result[0] = SPI1_ReadWriteByte(0xFF);
        times++;
    }while((sd_result[0]&0b10000000)&&(times<50));
//    for(uint8_t i=1;i<6;i++){
//        sd_result[i] = SPI1_ReadWriteByte(0xFF);
//    }
    return sd_result;
}
uint8_t *sd_response_2(char cmd){
    uint16_t times=0;
    do{
        sd_result[0] = SPI1_ReadWriteByte(0xFF);
        times++;
    }while((sd_result[0]&0b10000000)&&(times<50));
    for(uint8_t i=1;i<2;i++){
        sd_result[i] = SPI1_ReadWriteByte(0xFF);
    }
    return sd_result;
}
uint8_t *sd_response_3(char cmd){
    uint16_t times=0;
    do{
        sd_result[0] = SPI1_ReadWriteByte(0xFF);
        times++;
    }while((sd_result[0]&0b10000000)&&(times<50));
    for(uint8_t i=1;i<5;i++){
        sd_result[i] = SPI1_ReadWriteByte(0xFF);
    }
    return sd_result;
}
uint8_t *sd_response_6(char cmd){
    uint16_t times=0;
    do{
        sd_result[0] = SPI1_ReadWriteByte(0xFF);
        times++;
    }while(sd_result[0]!=(cmd&0b00111111)&&(times<50));
    for(uint8_t i=1;i<5;i++){
        sd_result[i] = SPI1_ReadWriteByte(0xFF);
    }
    return sd_result;
}
uint8_t *sd_response_7(char cmd){
    uint16_t times=0;
    do{
        sd_result[0] = SPI1_ReadWriteByte(0xFF);
        times++;
    }while((sd_result[0]&0b10000000)&&(times<50));
    for(uint8_t i=1;i<5;i++){
        sd_result[i] = SPI1_ReadWriteByte(0xFF);
    }
    return sd_result;
}
///---------------- 回复类型处理 ----------------
YZF_RECV MicroSDData={0};
uint8_t sd_response_data_token(){
    uint8_t data=0;
    //起始符读取
    do{
        data = SPI1_ReadWriteByte(0xFF);
    } while ((data&(0b00010001))!=0b00000001);
    return data;
}
uint32_t sd_write_wait(){
    uint32_t trys=0;
    uint8_t data=0;
    do{
        data = SPI1_ReadWriteByte(0xFF);
        trys++;
    } while ((data==0x00)&&(trys<10000));
    return trys;
}
uint8_t * sd_response_block_read(char cmd,uint16_t length,YZF_RECV *area){
    uint16_t times=0;

    uint8_t data=0;
    //起始符读取
    do{
        data = SPI1_ReadWriteByte(0xFF);
        times++;
    }while(data!=(MicroSD_READ_TOKEN));

    //数据读取
    for(uint16_t i=0;i<length;i++){
        yzf_area_recv_add(area,SPI1_ReadWriteByte(0xFF));
    }

    //crc位
    sd_result[1]=SPI1_ReadWriteByte(0xFF);
    sd_result[2]=SPI1_ReadWriteByte(0xFF);

    return yzf_area_recv_get_read_ptr(area);
}
//写处理
uint8_t sd_response_block_write(char cmd,uint16_t length,YZF_RECV *area,uint16_t count){
    uint8_t res=0;
    uint32_t trys=0;
    if(cmd==0x58){
        SPI1_ReadWriteByte(0xFF);
        //发送起始符
        SPI1_ReadWriteByte(MicroSD_SINGLE_WRITE_TOKEN);
        //数据读取
        for(uint16_t i=0;i<length;i++){
//            SPI1_ReadWriteByte(yzf_area_recv_get(area));
            SPI1_ReadWriteByte(0x20);
        }

        SPI1_ReadWriteByte(0xFF);
        SPI1_ReadWriteByte(0xFF);
        res=sd_response_data_token();
        trys=sd_write_wait();
        printf("写入等待次数: %ld\n",trys);
    }else if(cmd==0x59){
        SPI1_ReadWriteByte(0xFF);
        SPI1_ReadWriteByte(MicroSD_MULTIPLE_WRITE_TOKEN_START);
        for(uint16_t i=0;i<count;i++){
            for(uint16_t j=0;i<length;i++){
                SPI1_ReadWriteByte(yzf_area_recv_get(area));
            }
            res=sd_response_data_token();
            if((res&0b00011111)!=0b00000101){
                return res;
            }
        }
        SPI1_ReadWriteByte(MicroSD_MULTIPLE_WRITE_TOKEN_END);
    }
    return res;
}
uint8_t *SentCommandToMicroSDV2(char cmd,uint32_t data,uint8_t crc,enum SD_Response res_type){
    SPI1_ReadWriteByteStart();
    //数据传输
//    MicroSD_CS_SET;
//    SPI1_ReadWriteByte(0xff);
//    MicroSD_CS_RESET;

    char result=0,times=0;
    MicroSD_CS_SET;//禁止SD卡片选 同步时钟
    SPI1_ReadWriteByte(0xff);
    MicroSD_CS_RESET;//开始传输
    // SPI1_ReadWriteByte(0xff);

    SPI1_ReadWriteByte(cmd | 0b01000000);
    for(times=0;times<4;times++)
    {
        SPI1_ReadWriteByte((data>>24)&0xff);
        data<<=8;
    }

    SPI1_ReadWriteByte((crc<<1) + 1);
    uint8_t *res;
    //数据传输
    switch (res_type) {
        case SD_Response_0:
            res=sd_response_0(cmd);
            break;
        case SD_Response_1:
            res=sd_response_1(cmd);
            break;
        case SD_Response_2:
            res=sd_response_2(cmd);
            break;
        case SD_Response_3:
            res=sd_response_3(cmd);
            break;
        case SD_Response_6:
            res=sd_response_6(cmd);
            break;
        case SD_Response_7:
            res=sd_response_7(cmd);
            break;
        case SD_Response_NONE:
            res=sd_response_1(cmd);
            return res;
        default:
            res=YZF_NULL_PTR;
    }

    SPI1_ReadWriteByteEnd();
    MicroSD_CS_SET;//禁止SD卡片选 同步时钟
    return res;
}
uint8_t *yz_sd_get_result(){
    return sd_result;
}
YZF_RESULT yz_sd_spi_cmd0(YZF_SPI_POINTER spi){
    int retry=0;
    do{
        SentCommandToMicroSDV2(0x40,0,0x4A,SD_Response_0);
        retry++;
        if(retry>800)
        {
            return YZF_ERROR;
        }
    }
    while(sd_result[0]!=0x01);
    return YZF_OK;
}
YZF_RESULT yz_sd_spi_cmd8(YZF_SPI_POINTER spi){
    int retry=0;
    do{
        SentCommandToMicroSDV2(0x48,0x0000010E,0x14,SD_Response_7);
        retry++;
        if(retry>800)
        {
            return YZF_ERROR;
        }
    }
    while (sd_result[0]!=0x01);
    return YZF_OK;
}
YZF_RESULT yz_sd_spi_cmd9(YZF_SPI_POINTER spi){
    int retry=0;
    do{
        SentCommandToMicroSDV2(0x49,0x00000000,0x57,SD_Response_NONE);
        retry++;
        if(retry>800)
        {
            SPI1_ReadWriteByteEnd();
            return YZF_ERROR;
        }
    }
    while (sd_result[0]!=0x01);
    sd_response_block_read(0x49,16,&MicroSDData);
    SPI1_ReadWriteByteEnd();
    return YZF_OK;
}
YZF_RESULT yz_sd_spi_cmd10(YZF_SPI_POINTER spi){
    int retry=0;
    do{
        SentCommandToMicroSDV2(0x4a,0x00000000,0x0D,SD_Response_NONE);
        retry++;
        if(retry>800)
        {
            SPI1_ReadWriteByteEnd();
            return YZF_ERROR;
        }
    }
    while (sd_result[0]!=0x01);
    sd_response_block_read(0x4a,16,&MicroSDData);
    SPI1_ReadWriteByteEnd();
    return YZF_OK;
}
//STOP Transmit
YZF_RESULT yz_sd_spi_cmd12(YZF_SPI_POINTER spi){
    int retry=0;
    do{
        SentCommandToMicroSDV2(0x4c,0x00000000,0x30,SD_Response_1);
        retry++;
        if(retry>800)
        {
            return YZF_ERROR;
        }
    }
    while (sd_result[0]!=0x01);
    return YZF_OK;
}
YZF_RESULT yz_sd_spi_cmd13(YZF_SPI_POINTER spi){
    int retry=0;
    do{
        SentCommandToMicroSDV2(0x4d,0x00000000,0x06,SD_Response_2);
        retry++;
        if(retry>800)
        {
            return YZF_ERROR;
        }
    }
    while (sd_result[0]!=0x01);
    return YZF_OK;
}
YZF_RESULT yz_sd_spi_cmd17(YZF_SPI_POINTER spi,uint32_t sector,YZF_RECV *area){
    uint16_t retry=0;
    do{
        SentCommandToMicroSDV2(0x51,sector,0xff,SD_Response_NONE);
        if(sd_result[0]==0x01){
            sd_response_block_read(0x51,512,area);
        }
        retry++;
        if(retry>800)
        {
            SPI1_ReadWriteByteEnd();
            return YZF_ERROR;
        }
    } while (sd_result[0]!=0x01);
    SPI1_ReadWriteByteEnd();
    return YZF_OK;
}
YZF_RESULT yz_sd_spi_cmd18(YZF_SPI_POINTER spi,uint32_t sector,YZF_RECV *area,uint16_t len){
    uint16_t retry=0;
    do{
        SentCommandToMicroSDV2(0x52,sector,0xff,SD_Response_NONE);
        if(sd_result[0]==0x01){
            for(uint16_t i=0;i<len;i++){
                sd_response_block_read(0x51,512,area);
            }
            yz_sd_spi_cmd12(spi);
        }
        retry++;
        if(retry>800)
        {
            SPI1_ReadWriteByteEnd();
            return YZF_ERROR;
        }
    } while (sd_result[0]!=0x01);
    SPI1_ReadWriteByteEnd();
    return YZF_OK;
}
//单块写
YZF_RESULT yz_sd_spi_cmd24(YZF_SPI_POINTER spi,uint32_t sector,YZF_RECV *area){
    uint16_t retry=0;
    uint16_t data=0;
    do{
        SentCommandToMicroSDV2(0x58,sector,0xff,SD_Response_NONE);
        if(sd_result[0]==0x01){
            data=sd_response_block_write(0x58,512,area,1);
        }
        retry++;
        if(retry>800)
        {
            SPI1_ReadWriteByteEnd();
            return YZF_ERROR;
        }
    } while (sd_result[0]!=0x01);
    SPI1_ReadWriteByteEnd();
    if((data&0b00011111)!=0b00000101){
        return YZF_ERROR;
    }
    return YZF_OK;
}
//多块写
YZF_RESULT yz_sd_spi_cmd25(YZF_SPI_POINTER spi,uint32_t sector,YZF_RECV *area,uint16_t count){
    uint16_t retry=0;
    uint16_t data=0;
    do{
        SentCommandToMicroSDV2(0x59,sector,0xff,SD_Response_NONE);
        if(sd_result[0]==0x01){
            data=sd_response_block_write(0x59,512,area,count);
        }
        retry++;
        if(retry>800)
        {
            SPI1_ReadWriteByteEnd();
            return YZF_ERROR;
        }
    } while (sd_result[0]!=0x01);
    SPI1_ReadWriteByteEnd();
    //判断SD返回
    if((data&0b00011111)!=0b00000101){
        return YZF_ERROR;
    }
    return YZF_OK;
}
YZF_RESULT yz_sd_spi_cmd55(YZF_SPI_POINTER spi){
    int retry=0;
    do
    {
        SentCommandToMicroSDV2(0x77,0,0x32,SD_Response_1);
        retry++;
        if(retry>800)
        {
            return YZF_ERROR;
        }
    }
    while(sd_result[0]!=0x01);
    return YZF_OK;
}
YZF_RESULT yz_sd_spi_acmd41(YZF_SPI_POINTER spi){
    int retry=0;
    do
    {
        SentCommandToMicroSDV2(0x69,0x40000000,0x3B,SD_Response_3);
        retry++;
        if(retry>800)
        {
            return YZF_ERROR;
        }
    }
    while(sd_result[0]!=0x01); //回应01h，停止写入
    return YZF_OK;
}
YZF_RESULT yz_sd_spi_cmd42(YZF_SPI_POINTER spi){
    int retry=0;
    do
    {
        SentCommandToMicroSDV2(0x6a,0x00000000,0x28,SD_Response_1);
        retry++;
        if(retry>800)
        {
            return YZF_ERROR;
        }
    }
    while(sd_result[0]!=0x01); //回应01h，停止写入
    return YZF_OK;
}
YZF_RESULT yz_sd_spi_cmd58(YZF_SPI_POINTER spi){
    //get OCR
    int retry=0;
    do{
        SentCommandToMicroSDV2(0x7a,0x00000000,0x7E,SD_Response_3);
        retry++;
        if(retry>800)
        {
            return YZF_ERROR;
        }
    } while (sd_result[0]!=0x01);
    return YZF_OK;
}
YZF_RESULT yz_sd_spi_cmd59(YZF_SPI_POINTER spi){
    //off crc
    int retry=0;
    do{
        SentCommandToMicroSDV2(0x7b,0x00000000,0x48,SD_Response_1);
        retry++;
        if(retry>800)
        {
            return YZF_ERROR;
        }
    } while (sd_result[0]!=0x01);
    return YZF_OK;
}

//初始化化不是很稳定也就是说明传输数据可能不是很稳定
char SD_Init(void)
{

    char i,temp=0;
    //char CMD[] = {0x40,0x00,0x00,0x00,0x00,0x95};
    int retry=0;

    MicroSD_CS_SET;
    //发送至少74个时钟信号，数据顺便填写
    printf("Start Sign ...\n");

    for (i=0;i<0x2f;i++){SPI1_ReadWriteByte(0xff);}

    printf("Start Sign OK!\n");
    //CMD0
    if(yz_sd_spi_cmd0(MicroSD_SPI)==YZF_ERROR){
        printf("CMD0 Error! CODE:%d",sd_result[0]);
        return YZF_ERROR;
    }
    printf("CMD0 OK!\n");

    if(yz_sd_spi_cmd8(MicroSD_SPI)==YZF_ERROR){
        printf("CMD8 Error! CODE:%d",sd_result[0]);
        return YZF_ERROR;
    }
    printf("CMD8 OK!\n");

    if(yz_sd_spi_cmd55(MicroSD_SPI)==YZF_ERROR){
        printf("CMD55 Error! CODE:%d",sd_result[0]);
        return YZF_ERROR;
    }
    printf("CMD55 OK!\n");

    if(yz_sd_spi_acmd41(MicroSD_SPI)==YZF_ERROR){
        printf("ACMD41 Error! CODE:%d",sd_result[0]);
        return YZF_ERROR;
    }
    printf("ACMD41 OK!\n");
    //off crc
    if(yz_sd_spi_cmd59(MicroSD_SPI)==YZF_ERROR){
        printf("CMD59 Error! CODE:%d",sd_result[0]);
        return YZF_ERROR;
    }
    printf("CMD59 OK!\n");
    //get ocr
    if(yz_sd_spi_cmd58(MicroSD_SPI)==YZF_ERROR){
        printf("CMD58 Error! CODE:%d",sd_result[0]);
        return YZF_ERROR;
    }
    printf("CMD58 OK!\n");
    ///Get SD Card's Information to MicroSDData {[0:127]:CID,[128:255]:CSD}
    //CID
    if(yz_sd_spi_cmd10(MicroSD_SPI)==YZF_ERROR){
        printf("CMD10 Error! CODE:%d",sd_result[0]);
        return YZF_ERROR;
    }
    printf("CMD10 OK!\n");

    //CSD
    if(yz_sd_spi_cmd9(MicroSD_SPI)==YZF_ERROR){
        printf("CMD9 Error! CODE:%d",sd_result[0]);
        return YZF_ERROR;
    }
    printf("CMD9 OK!\n");

    //to high speed
//    yzf_spi_disable(MicroSD_SPI);
//    yzf_spi_set_br(MicroSD_SPI,YZF_SPI_PLCK_4);
//    yzf_spi_enable(MicroSD_SPI);
    MicroSD_CS_SET;  //片选无效
    return 0;
}

YZF_RESULT WriteSectorToMicroSD(long addr,YZF_RECV *area)
{
    if(yz_sd_spi_cmd24(MicroSD_SPI,addr,area)==YZF_ERROR){
        printf("CMD24 Error! CODE:%d",sd_result[0]);
        return YZF_ERROR;
    }
    printf("CMD24 OK!\n");
    return 0;
}
YZF_RESULT WriteSectorsToMicroSD(long addr,YZF_RECV *area,uint16_t len)
{
    if(yz_sd_spi_cmd25(MicroSD_SPI,addr,area,len)==YZF_ERROR){
        printf("CMD25 Error! CODE:%d",sd_result[0]);
        return YZF_ERROR;
    }
    printf("CMD25 OK!\n");
    return 0;
}
YZF_RESULT ReadSectorsFromMicroSD(long sector,YZF_RECV *area,uint16_t len){
    if(yz_sd_spi_cmd18(MicroSD_SPI,sector,area,len)==YZF_ERROR){
        return YZF_ERROR;
    }
    return YZF_OK;
}
YZF_RESULT ReadSectorFromMicroSD(long sector,YZF_RECV *area)
{
    if(yz_sd_spi_cmd17(MicroSD_SPI,sector,area)==YZF_ERROR){
        printf("CMD17 Error! CODE:%d",sd_result[0]);
        return YZF_ERROR;
    }
    printf("CMD17 OK!\n");
    return YZF_OK;
}